import ApiList from './ApiList.json'
import axios from "axios";

class ApiInvoker {
  constructor(v, apiGroup) {
    this.v = v;
    this.apiGroup = apiGroup;
  }

  conver(data, index, final) {
    if (typeof data !== 'object') {
      data = {};
    }
    data.index = index;
    data.final = final;
    return data;
  }

  get apiList() {
    return ApiList[this.apiGroup];
  }

  set format(call) {
    if (typeof call != 'function') {
      return;
    }
    this.conver = call;
  }

  objectCopy(...os) {
    let nO = {}, rms = [];
    for (let o of os) {
      for (let z in o) {
        if (o[z] === '#rm') {
          rms.push([z]);
          continue;
        }
        nO[z] = o[z];
      }
    }
    for (let rm in rms) {
      delete nO[rm];
    }
    return nO;
  }


  invoker(name, param, postBody, method, config) {
    let self = this;
    return {
      method: method, postBody: postBody, config: config, lastParam: {},
      // then() {
      //
      // },
      executeArray(cb, method, syncParam, config) {
        let transformObjToArr = (data, isRoot = true) => {
          if (!data || typeof data !== 'object') return data;
          let dataNew = [];
          let keys = Object.keys(data);
          if (keys.includes('0')) {
            keys.forEach(k => dataNew[k] = transformObjToArr(data[k], false));
          } else {
            keys.forEach(k => data[k] = transformObjToArr(data[k], false));
          }
          if (isRoot) {
            return dataNew.length ? JSON.stringify(dataNew) : JSON.stringify(data);
          } else {
            return dataNew.length ? dataNew : data;
          }
        }
        let that = this, np = null;
        if (ApiList[self.apiGroup][name].config) {
          np = param || syncParam;
        } else if (syncParam) {
          np = self.objectCopy(ApiList[self.apiGroup][name].defaultParam, param, syncParam);
        } else if (this.lastParam[name]) {
          np = this.lastParam[name];
        } else {
          np = self.objectCopy(ApiList[self.apiGroup][name].defaultParam, param);
        }
        let req = axios.create({
          method: "POST",
          headers: {
            'Content-Type': 'application/json;',
            'Authorization': window.localStorage.getItem('token')
          },
          transformRequest: [
            (data) => {
              return transformObjToArr(data)
            }
          ]
        });
        return req({url: ApiList[self.apiGroup][name].url, data: np, param: np}).then(resp => {
          cb && cb(self.conver(resp));
          that.lastParam[name] = np;
        });
      },
      execute(cb, method, syncParam, config, index, final) {
        let that = this, np = null;
        if (ApiList[self.apiGroup][name].config) {
          np = param || syncParam;
        } else if (syncParam) {
          np = self.objectCopy(ApiList[self.apiGroup][name].defaultParam, param, syncParam);
        } else if (this.lastParam[name]) {
          np = this.lastParam[name];
        } else {
          np = self.objectCopy(ApiList[self.apiGroup][name].defaultParam, param);
        }
        let addUrl = '';
        if (np.urlParam) {
          addUrl = '/' + np.urlParam;
          np = null;
        }
        if ((this.method || method) === 'get') {
          self.v.$get(ApiList[self.apiGroup][name].url, np).then(resp => {
            cb && cb(self.conver(resp), index, final);
            that.lastParam[name] = np;
          });
          return that;
        }
        return self.v.$post(ApiList[self.apiGroup][name].url + addUrl, np, (this.postBody || postBody) ? {emulateJSON: true} :
          (this.config || config || ApiList[self.apiGroup][name].config || {})).then(resp => {
          cb && cb(self.conver(resp), index, final);
          that.lastParam[name] = np;
        }).catch(err => {
        });
      }
    }
  }

// eslint-disable-next-line no-empty
  invokerList(list) {
    if (typeof list !== 'object') {
      return;
    }
    let invokerList = [];
    for (let task of list) {
      invokerList.push(this.invoker(task.name, task.param || {}, task.postBody));
    }
    return {
      async execute(cb, syncParam) {
        let taskSize = invokerList.length, index = 0, result = [];
        for (let vk of invokerList) {
          let ccb = (data, index, done) => {
            cb && cb(data, index, done);
            result.push(data);
          }
          await vk.execute(ccb, vk.method, syncParam, vk.postBody, index++, taskSize === index);
        }
        return Promise.resolve(result);
      }
    }

  }
}

let instance = 0;

export default {
  newInstance(v, create, apiGroup, cover) {
    if (cover || !instance) {
      instance = new ApiInvoker(v, apiGroup);
    }
    if (create) {
      return new ApiInvoker(v, apiGroup);
    }
    return instance;
  },

  nativeGet(url, cb) {
    let xhr = new XMLHttpRequest();
    xhr.open("get", url, true);
    xhr.responseType = "blob";
    xhr.onload = function () {
      if (this.status == 200) {
        const reader = new FileReader()
        reader.onload = () => {
          cb(reader.result);
        }
        reader.readAsText(this.response);
      }
    };
    xhr.send();
  }
}
